package start

import (
	"context"
	"fmt"
	"gitee.com/filters/logger"
	"gitee.com/filters/reader/wviper"
	"gitee.com/filters/start/proxy"
	"gitee.com/filters/start/refer"
	"gitee.com/filters/start/safe_map"
	"gitee.com/filters/utils/character"
	"gitee.com/filters/utils/conversion"
	"github.com/gin-gonic/gin"
	"github.com/goccy/go-json"
	"github.com/spf13/cast"
	"github.com/tidwall/gjson"
	"io"
	"net/http"
	"reflect"
	"strings"
	"sync"
	"time"
)

var (
	config         *wviper.Reader
	defaultContext = &gin.Context{}
	DefaultGinTime = 10 * time.Second
)

type GrpcHttpServer struct {
	*GrpcServer
	*GinServer
	filter  []*HttpFilter
	white   *HttpFilter
	methods *Methods
}

type TypeFilter int32

const (
	MixFilter   TypeFilter = 1
	WhiteFilter TypeFilter = 2
)

const (
	FieldJson     = "json"
	FieldProtobuf = "protobuf"
)

type DeleteMethods []string
type GetMethods []string
type PostMethods []string
type PatchMethods []string
type OPTIONSMethods []string
type HEADMethods []string
type AnyMethods []string

type MethodList interface {
	Get() reflect.Type
}
type Methods struct {
	DeleteMethods
	GetMethods
	PostMethods
	PatchMethods
	OPTIONSMethods
	HEADMethods
	AnyMethods
}

func (m *Methods) Num() int {
	return reflect.TypeOf(m).NumField()
}

func (m *Methods) Field(i int) reflect.StructField {
	return reflect.TypeOf(m).Field(i)
}

func (d DeleteMethods) Get() reflect.Type {
	return reflect.TypeOf(d)
}
func (d GetMethods) Get() reflect.Type {
	return reflect.TypeOf(d)
}
func (d PostMethods) Get() reflect.Type {
	return reflect.TypeOf(d)
}
func (d OPTIONSMethods) Get() reflect.Type {
	return reflect.TypeOf(d)
}
func (d PatchMethods) Get() reflect.Type {
	return reflect.TypeOf(d)
}

func (d HEADMethods) Get() reflect.Type {
	return reflect.TypeOf(d)
}

func (d AnyMethods) Get() reflect.Type {
	return reflect.TypeOf(d)
}

// HttpFilter 白名单
type HttpFilter struct {
	WhiteList []string //过滤不需要鉴权的函数
	Func      gin.HandlerFunc
	Type      TypeFilter
}

func GinSet(ctx context.Context, key string, value any) {
	defaultContext.Set(key, value)
}
func GinGet(ctx context.Context, key string) (value any, exists bool) {
	value, exists = defaultContext.Get(key)
	return
}

func GetGin(ctx context.Context) *gin.Context {
	return defaultContext
}

func GetCtx(ctxs context.Context) context.Context {
	ctx, cancel := context.WithTimeout(ctxs, DefaultGinTime)
	defer cancel()
	return ctx
}

func NewGrpcHttp(cfgMap []GrpcCfgMap) *GrpcHttpServer {
	g := &GrpcHttpServer{
		GrpcServer: NewGrpc(cfgMap),
		GinServer:  NewGin(),
		methods:    &Methods{},
	}
	return g
}

func (g *GrpcHttpServer) HandlerFilter(middle ...*HttpFilter) *GrpcHttpServer {
	for _, filter := range middle {
		if filter.Type == MixFilter {
			g.filter = append(g.filter, filter)
		}
		if filter.Type == WhiteFilter {
			g.white = filter
		}
	}
	return g
}

// Method 请求方式
func (g *GrpcHttpServer) Method(list ...MethodList) *GrpcHttpServer {
	for _, methodList := range list {
		if reflect.TypeOf(methodList) == (PatchMethods{}).Get() {
			g.methods.PatchMethods = methodList.(PatchMethods)
		}
		if reflect.TypeOf(methodList) == (GetMethods{}).Get() {
			g.methods.GetMethods = methodList.(GetMethods)
		}
		if reflect.TypeOf(methodList) == (DeleteMethods{}).Get() {
			g.methods.DeleteMethods = methodList.(DeleteMethods)
		}
		if reflect.TypeOf(methodList) == (PostMethods{}).Get() {
			g.methods.PostMethods = methodList.(PostMethods)
		}
		if reflect.TypeOf(methodList) == (OPTIONSMethods{}).Get() {
			g.methods.OPTIONSMethods = methodList.(OPTIONSMethods)
		}
		if reflect.TypeOf(methodList) == (HEADMethods{}).Get() {
			g.methods.HEADMethods = methodList.(HEADMethods)
		}
		if reflect.TypeOf(methodList) == (AnyMethods{}).Get() {
			g.methods.AnyMethods = methodList.(AnyMethods)
		}
	}
	return g
}

func (g *GrpcHttpServer) writeRouter(paths RouteName, grpcCli *proxy.Client, port interface{}) {
	var flag = false
	if len(g.methods.DeleteMethods) > 0 &&
		character.ContainString(g.methods.DeleteMethods, paths.Name) {
		flag = true
		g.engine.DELETE(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}
	if len(g.methods.GetMethods) > 0 &&
		character.ContainString(g.methods.GetMethods, paths.Name) {
		flag = true
		g.engine.GET(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}

	if len(g.methods.PostMethods) > 0 &&
		character.ContainString(g.methods.PostMethods, paths.Name) {
		flag = true
		g.engine.POST(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}

	if len(g.methods.PatchMethods) > 0 &&
		character.ContainString(g.methods.PatchMethods, paths.Name) {
		flag = true
		g.engine.PATCH(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}

	if len(g.methods.OPTIONSMethods) > 0 &&
		character.ContainString(g.methods.OPTIONSMethods, paths.Name) {
		flag = true
		g.engine.OPTIONS(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}

	if len(g.methods.HEADMethods) > 0 &&
		character.ContainString(g.methods.HEADMethods, paths.Name) {
		flag = true
		g.engine.HEAD(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}

	if len(g.methods.AnyMethods) > 0 &&
		character.ContainString(g.methods.AnyMethods, paths.Name) {
		flag = true
		g.engine.Any(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}
	if !flag {
		g.engine.POST(paths.Path, func(ctx *gin.Context) {
			paths.query(ctx, grpcCli, port)
		})
	}
}

// query http去请求grpc服务
func (paths RouteName) query(ctx *gin.Context, grpcCli *proxy.Client, port interface{}) {
	defaultContext = ctx
	data, err := io.ReadAll(ctx.Request.Body)
	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{
			"ret": http.StatusNotImplemented,
			"msg": character.DecodeIfEncoded(err.Error()),
		})
		return
	}
	source := gjson.ParseBytes(data)
	temp := safe_map.ConfigSafeMap{}
	for s := 0; s < paths.ReqType.NumField(); s++ {
		field := paths.ReqType.Field(s)
		if strings.HasPrefix(field.Name, "state") ||
			strings.HasPrefix(field.Name, "sizeCache") ||
			strings.HasPrefix(field.Name, "unknownFields") {
			continue
		}

		name := paths.ReqType.Field(s).Tag.Get(FieldJson)
		firstField, _, _ := strings.Cut(name, ",")
		if source.Get(paths.ReqType.Field(s).Name).Exists() {
			temp.Set(paths.ReqType.Field(s).Name, source.Get(paths.ReqType.Field(s).Name).Value())
		}
		if source.Get(firstField).Exists() {
			temp.Set(firstField, source.Get(firstField).Value())
		}
	}
	tempString, _ := json.Marshal(temp.Data)
	// 创建metadata并添加Gin Context中的值
	var md = safe_map.ConfigSafeMap{}
	// 添加请求头到metadata
	for key, values := range ctx.Request.Header {
		md.Set(key, strings.Join(values, ","))
	}
	for key, value := range ctx.Keys {
		if strVal, ok := value.(string); ok {
			md.Set(key, strVal)
		} else {
			// 非字符串值转换为JSON字符串
			jsonVal, _ := json.Marshal(value)
			md.Set(key, string(jsonVal))
		}
	}
	r, err := grpcCli.PostWithMetadata(fmt.Sprintf("127.0.0.1:%d", port), paths.Path, tempString, md)
	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{
			"ret": http.StatusBadGateway,
			"msg": character.DecodeIfEncoded(err.Error()),
		})
		return
	}
	reqV := reflect.New(paths.RspType)
	err = ToStruct(string(r), paths.RspType, reqV)
	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{
			"ret": http.StatusServiceUnavailable,
			"msg": character.DecodeIfEncoded(err.Error()),
		})
		return
	}

	ctx.JSON(http.StatusOK, reqV.Interface())
}

// ToStruct 将JSON字符串转换为结构体
func ToStruct(source string, ty reflect.Type, val reflect.Value) error {
	// 解析JSON字符串
	var data safe_map.ConfigSafeMap
	if err := json.Unmarshal([]byte(source), &data.Data); err != nil {
		return err
	}

	// 处理指针类型
	if val.Kind() == reflect.Ptr {
		if val.IsNil() {
			val.Set(reflect.New(val.Type().Elem()))
		}
		val = val.Elem()
	}

	for i := 0; i < val.NumField(); i++ {
		// 跳过protobuf生成的特殊字段
		fieldName := ty.Field(i).Name
		if strings.HasPrefix(fieldName, "state") ||
			strings.HasPrefix(fieldName, "sizeCache") ||
			strings.HasPrefix(fieldName, "unknownFields") {
			continue
		}

		field := val.Field(i)
		fieldType := ty.Field(i).Type
		jsonTag := ty.Field(i).Tag.Get(FieldJson)
		jsonName := strings.Split(jsonTag, ",")[0] // 获取json标签名
		var protofName string
		protofTag := ty.Field(i).Tag.Get(FieldProtobuf)
		if protofTag != "" {
			temp := strings.Split(protofTag, "json=")
			if len(temp) > 1 {
				protofName = strings.Split(temp[1], ",")[0]
			}
		}

		// 优先使用json标签名查找，没有则使用字段名
		var key string
		if jsonName != "" {
			key = jsonName
		} else {
			key = fieldName
		}

		// 从source数据中获取值
		value, exists := data.Gets(key)

		if !exists {
			// 从source数据中获取值
			value, exists = data.Gets(protofName)
			if !exists {
				continue
			}
		}

		// 处理嵌套指针类型
		if field.Kind() == reflect.Ptr {
			if field.IsNil() {
				field.Set(reflect.New(fieldType.Elem()))
			}
			// 递归处理嵌套结构
			if nestedVal, err := json.Marshal(value); err == nil {
				if err := ToStruct(string(nestedVal), fieldType.Elem(), field.Elem()); err != nil {
					return err
				}
			}
			continue
		}
		if field.Kind() == reflect.Slice || field.Kind() == reflect.Array {
			sliceValue := reflect.ValueOf(value)
			if sliceValue.Kind() == reflect.Slice {
				// 创建对应类型的切片
				field.Set(reflect.MakeSlice(fieldType, sliceValue.Len(), sliceValue.Len()))
				for i := 0; i < sliceValue.Len(); i++ {
					elem := sliceValue.Index(i)
					if elem.Kind() == reflect.Interface {
						elem = elem.Elem()
					}

					// 处理切片元素
					if fieldType.Elem().Kind() == reflect.Ptr && fieldType.Elem().Elem().Kind() == reflect.Struct {
						// 处理指针类型的结构体元素
						if elem.Kind() == reflect.Map {
							if nestedVal, err := json.Marshal(elem.Interface()); err == nil {
								newElem := reflect.New(fieldType.Elem().Elem())
								if err := ToStruct(string(nestedVal), fieldType.Elem().Elem(), newElem.Elem()); err == nil {
									field.Index(i).Set(newElem)
								}
							}
						}
					} else if fieldType.Elem().Kind() == reflect.Struct {
						// 处理结构体类型的元素
						if elem.Kind() == reflect.Map {
							if nestedVal, err := json.Marshal(elem.Interface()); err == nil {
								if err := ToStruct(string(nestedVal), fieldType.Elem(), field.Index(i)); err != nil {
									return err
								}
							}
						}
					} else {
						// 基本类型直接赋值
						if elem.Type().ConvertibleTo(fieldType.Elem()) {
							field.Index(i).Set(elem.Convert(fieldType.Elem()))
						}
					}
				}
			}
			continue
		}
		// 处理基本类型
		if field.CanSet() {
			Convert(field, value, fieldType)
		}
	}

	return nil
}

func Convert(field reflect.Value, value interface{}, fieldType reflect.Type) {
	switch fieldType.Kind() {
	case reflect.String:
		field.SetString(cast.ToString(value))
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		field.SetInt(cast.ToInt64(value))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		field.SetUint(cast.ToUint64(value))
	case reflect.Float32, reflect.Float64:
		field.SetFloat(cast.ToFloat64(value))
	case reflect.Bool:
		field.SetBool(cast.ToBool(value))
	default:
		if field.Type().ConvertibleTo(fieldType) {
			field.Set(reflect.ValueOf(value).Convert(fieldType))
		}
	}
}

func (g *GrpcHttpServer) LoadConfig(opt ...wviper.Option) (map[string]interface{}, error) {
	cfg, err := wviper.NewSetting(opt...)
	if err != nil {
		return nil, err
	}
	if _, ok := cfg.Get(GinConfig).(map[string]interface{}); !ok {
		return nil, refer.ErrorNotFoundConfigInfo
	}
	g.ginConfig.Data = cfg.Get(GinConfig).(map[string]interface{})

	if _, ok := cfg.Get(GrpcCfg).(map[string]interface{}); !ok {
		return nil, refer.ErrorNotFoundConfigInfo
	}
	g.grpcConfig.Data = cfg.Get(GrpcCfg).(map[string]interface{})
	return cfg.Get(GrpcCfg).(map[string]interface{}), nil
}

type RouteName struct {
	Path    string
	Name    string
	ReqType reflect.Type
	RspType reflect.Type
}

func (g *GrpcHttpServer) Run() error {
	var (
		normalityList []RouteName
		whiteList     []RouteName
		client        = proxy.NewClient()
	)
	for _, cfgMaps := range g.srvMap {
		t := reflect.TypeOf(cfgMaps.Service)
		vs := reflect.ValueOf(cfgMaps.SrvDesc)
		for i := 0; i < t.NumMethod(); i++ {
			path := "/" + strings.Join([]string{vs.Field(0).String(), t.Method(i).Name}, "/")
			if t.Method(i).Type.NumIn() >= 3 && t.Method(i).Type.NumOut() >= 2 {
				ty := t.Method(i).Type.In(2).Elem()
				oy := t.Method(i).Type.Out(0).Elem()
				if g.white != nil {
					if character.ContainString(g.white.WhiteList, t.Method(i).Name) {
						whiteList = append(whiteList, RouteName{
							Path:    path,
							ReqType: ty,
							RspType: oy,
							Name:    t.Method(i).Name,
						})
						continue
					}
				}
				normalityList = append(normalityList, RouteName{
					Path:    path,
					ReqType: ty,
					RspType: oy,
					Name:    t.Method(i).Name,
				})
			} else {
				return refer.ErrorReqLessThreeGinSrv
			}
		}
	}

	for _, filter := range g.filter {
		g.engine.Use(filter.Func)
	}
	if len(whiteList) > 0 {
		for _, s := range whiteList {
			g.writeRouter(s, client, g.grpcConfig.Get(GrpcPort))
		}
	}
	if len(normalityList) > 0 {
		if g.white != nil {
			g.engine.Use(g.white.Func)
		}
		for _, s := range normalityList {
			g.writeRouter(s, client, g.grpcConfig.Get(GrpcPort))
		}
	}

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		err := g.GrpcServer.Run()
		if err != nil {
			panic(err)
		}
	}()
	go func() {
		defer wg.Done()
		err := g.GinServer.Run()
		if err != nil {
			panic(err)
		}
	}()
	wg.Wait()
	return nil
}

// UseLog 日志记录
func (g *GrpcHttpServer) UseLog() *GrpcHttpServer {
	cfg := config.Get(logger.Logger).(map[string]interface{})
	logger.NewLog(logger.WithWritePath(cfg[logger.LogPathName].(string)),
		logger.WithLogExt(cfg[logger.LogExtName].(string))).CurLog().WrapFormat()
	return g
}

// BindField 绑定数据
func (g *GrpcHttpServer) BindField(f ...interface{}) *GrpcHttpServer {
	for _, i2 := range f {
		conversion.ToStruct(config.AllSettings(), i2)
	}
	return g
}

// HandleMiddleware 绑定中间件
func (g *GrpcHttpServer) HandleMiddleware(middles ...gin.HandlerFunc) *GrpcHttpServer {
	g.GinServer.HandleMiddleware(middles...)
	return g
}

// HandleAddFunc 定时执行函数
func (g *GrpcHttpServer) HandleAddFunc(list []*CronTabObj) *GrpcHttpServer {
	g.GinServer.HandleAddFunc(list)
	return g
}

// HandleRouter 绑定路由
func (g *GrpcHttpServer) HandleRouter(route func(r *gin.Engine)) *GrpcHttpServer {
	route(g.GinServer.engine)
	return g
}
